﻿using Dimeng.ArdisPostProcessor.HomagLC4.Ardis;
using ReadR41;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Dimeng.ArdisPostProcessor.HomagLC4Adsn
{
    public class Bootstrap
    {
        double limitCutWidth = 50;
        int analysisLevel = 1;
        double additonalTrimValue = 5;
        R41Data data;
        R41Data result1 = new R41Data("first"); //result1针对第一次切割的i情况
        R41Data result2 = new R41Data("second"); //result2针对第一次切割的条子进行二次切割
        public List<string> Result2Comments = new List<string>(); //为result2每一个pattern准备的备注，方便保存原始信息
        public Dictionary<int, ExternPart> Result2Parts = new Dictionary<int, ExternPart>();

        public Bootstrap(R41Data data, double trimValue, int analysisLevel, double limitcutwidth)
        {
            this.data = data;
            this.additonalTrimValue = trimValue;
            this.analysisLevel = analysisLevel;
            this.limitCutWidth = limitcutwidth;

            this.result1.ParameterList = new ParameterList();
            this.result1.Parts = new List<Part>();//因为有中间过度的strip作为板件打标签，所以板件清单重置
            this.result1.Materials = data.Materials;//保留原来的material信息
            this.result1.Patterns = new List<Pattern>();
            this.result1.Sheets = data.Sheets;//保留原来的sheets信息
            this.result1.Cuts = new List<Cut>();

            this.result2.ParameterList = new ParameterList();
            this.result2.Parts = data.Parts;//因为是原来parts的子集
            this.result2.Materials = data.Materials;//保留原来的material信息
            this.result2.Patterns = new List<Pattern>();
            this.result2.Sheets = new List<Sheet>();//不保留原来的sheets信息
            this.result2.Cuts = new List<Cut>();
        }

        public void Start()
        {
            //分析每一片板件
            foreach (var pattern in data.Patterns)
            {
                this.result1.Patterns.Add(pattern);//把这个pattern的信息加入到result1的

                var childCuts = data
                            .FullCuts
                            .Where(it => it.CutPatternNo == pattern.PatternNumber
                                && it.CutParentNo == 0
                                && it.CutLevel == 1
                                && (it.CutType != CutType.SawCut))
                            .ToList();//查找pattern的第一级子Cut

                double parentCutW = childCuts[0].CutD == 'H' ? pattern.PatternW : pattern.PatternL;

                //保存每个cut的结果
                List<CutResult> cutResult = new List<CutResult>();

                //第一次遍历计算，获取每个cut的余料情况，判断当前cut的数据是在第一结果还是第二结果
                for (int i = 0; i < childCuts.Count; i++)
                {
                    var cut = childCuts[i];

                    if (cut.CutType == CutType.SawCut)
                    {
                        throw new Exception();
                    }

                    cutResult.Add(calculateCutRest(cut));
                }

                //找到子cut，然后遍历，根据情况筛选
                loadCuts(childCuts, cutResult, 0, pattern, parentCutW);
            }
        }

        /// <summary>
        /// 分析每一个pattern的cut数据
        /// </summary>
        /// <param name="cuts">cut列表，过滤掉sawcut，只余下trim,part,strip,rest</param>
        /// <param name="parentNo">上一级的序号</param>
        /// <param name="pattern">原始的pattern</param>
        /// <param name="parentCutW">上一级的切割尺寸，用于计算当前的strip的长宽</param>
        private void loadCuts(List<ExternCut> cuts, List<CutResult> cutResult, int parentNo, Pattern pattern, double parentCutW)
        {
            //俩临时变量，保存要加入到第二结果的切割长度和子切数据
            double tempCutW = 0;
            List<ExternCut> tempCuts = new List<ExternCut>();

            //第二次遍历，根据第一次遍历的结果，决定是否保留这个切割到第一结果中
            for (int i = 0; i < cuts.Count; i++)
            {
                if (i == cuts.Count - 1)//如果是最后一个
                {
                    #region 最后一块的时候
                    if (cutResult[i] == CutResult.RestTrue && cutResult[i - 1] != CutResult.StripFalse)//余料保留，且上一条不是stripfalse
                    {
                        tempCuts.Add(cuts[i]);

                        Cut nc = new Cut();
                        nc.CutD = cuts[i - 1].CutD;
                        nc.CutLevel = cuts[i - 1].CutLevel;
                        //nc.CutNo = cuts[i].CutNo;
                        nc.CutNo = result1.Cuts.Count + 1;
                        nc.CutParentNo = parentNo;
                        nc.CutPartNo = result1.Parts.Count + 1;
                        nc.CutPatternNo = cuts[i - 1].CutPatternNo;
                        nc.CutQty = 1;
                        //nc.CutType = cuts[i].CutType;
                        nc.CutW = tempCutW + cuts[i].CutW + (tempCuts.Count - 1) * cuts[i].Kerf;
                        nc.Kerf = cuts[i].Kerf;
                        tempCutW = 0;
                        result1.Cuts.Add(nc);


                        //往result1的板件里加入这么一块板
                        addPartToResult1(tempCuts, nc, parentCutW, pattern, cuts[i - 1].CutPatternNo);


                        //同时往第二结果中塞入这么一个结果集
                        addCutsToResult2(this.result2, tempCuts, pattern, parentCutW, 0);
                        tempCuts.Clear();

                        continue;
                    }
                    else if (cutResult[i] == CutResult.RestFalse)
                    {
                        //result1.Cuts.Add(cuts[i]);
                    }
                    else
                    {
                        if (cutResult[i] == CutResult.RestTrue && cutResult[i - 1] == CutResult.StripFalse)//余料保留，且上一条不是stripfalse
                        {
                            continue;
                        }
                        else
                        {
                            throw new Exception("unknown cut result type!only accept rest true/false!");
                        }
                    }
                    #endregion
                }
                else if (cutResult[i] == CutResult.Trim)//因为届时还得再分析一次fullcuts，到时还会加入trim，所以这里trim不保留
                {
                    //result1.Cuts.Add(cuts[i]);
                }
                else if (cutResult[i] == CutResult.Part) //如果是板件，则要看下后续情况，再决定是否加入
                {
                    if (cutResult[i + 1] == CutResult.Part ||
                        cutResult[i + 1] == CutResult.RestTrue ||
                        cutResult[i + 1] == CutResult.StripTrue)
                    {
                        //如果是这些东西，就加入到第二结果中了
                        tempCutW += cuts[i].CutW;
                        tempCuts.Add(cuts[i]);
                    }
                    else
                    {
                        //如果tempCuts没有数据 说明会直接出板
                        if (tempCuts.Count == 0)
                        {

                        }

                        tempCuts.Add(cuts[i]);

                        Cut nc = new Cut();
                        nc.CutD = cuts[i].CutD;
                        nc.CutLevel = cuts[i].CutLevel;
                        nc.CutNo = result1.Cuts.Count + 1;
                        nc.CutParentNo = parentNo;
                        nc.CutPartNo = result1.Parts.Count + 1;
                        nc.CutPatternNo = cuts[i].CutPatternNo;
                        nc.CutQty = cuts[i].CutQty;
                        //nc.CutType = cuts[i].CutType;
                        nc.CutW = tempCutW + cuts[i].CutW + (tempCuts.Count - 1) * cuts[i].Kerf;
                        nc.Kerf = cuts[i].Kerf;
                        tempCutW = 0;
                        result1.Cuts.Add(nc);

                        //往result1的板件里加入这么一块板
                        addPartToResult1(tempCuts, nc, parentCutW, pattern, cuts[i].CutPatternNo);

                        addCutsToResult2(this.result2, tempCuts, pattern, parentCutW, 0);
                        tempCuts.Clear();
                    }
                }
                else if (cutResult[i] == CutResult.StripTrue)
                {
                    if (cutResult[i + 1] == CutResult.Part ||
                        cutResult[i + 1] == CutResult.RestTrue ||
                        cutResult[i + 1] == CutResult.StripTrue)
                    {
                        //如果是这些东西，就加入到第二结果中了
                        tempCutW += cuts[i].CutW;
                        tempCuts.Add(cuts[i]);
                    }
                    else
                    {
                        tempCuts.Add(cuts[i]);

                        Cut nc = new Cut();
                        nc.CutD = cuts[i].CutD;
                        nc.CutLevel = cuts[i].CutLevel;
                        nc.CutNo = result1.Cuts.Count + 1;
                        nc.CutParentNo = parentNo;
                        nc.CutPartNo = result1.Parts.Count + 1;
                        nc.CutPatternNo = cuts[i].CutPatternNo;
                        nc.CutQty = cuts[i].CutQty;
                        //nc.CutType = cuts[i].CutType;
                        nc.CutW = tempCutW + cuts[i].CutW + (tempCuts.Count - 1) * cuts[i].Kerf;
                        nc.Kerf = cuts[i].Kerf;
                        tempCutW = 0;
                        result1.Cuts.Add(nc);

                        //往result1的板件里加入这么一块板
                        addPartToResult1(tempCuts, nc, parentCutW, pattern, cuts[i].CutPatternNo);

                        addCutsToResult2(this.result2, tempCuts, pattern, parentCutW, 0);
                        tempCuts.Clear();
                    }
                }
                else if (cutResult[i] == CutResult.StripFalse)
                {
                    tempCuts.Add(cuts[i]);

                    Cut nc = new Cut();
                    nc.CutD = cuts[i].CutD;
                    nc.CutLevel = cuts[i].CutLevel;
                    nc.CutNo = result1.Cuts.Count + 1;
                    nc.CutParentNo = parentNo;
                    nc.CutPartNo = 0;// result1.Parts.Count + 1;
                    nc.CutPatternNo = cuts[i].CutPatternNo;
                    nc.CutQty = cuts[i].CutQty;
                    //nc.CutType = cuts[i].CutType;
                    nc.CutW = cuts[i].CutW;
                    nc.Kerf = cuts[i].Kerf;
                    tempCutW = 0;
                    result1.Cuts.Add(nc);

                    var restCut = this.data.FullCuts.Find(it => it.CutParentNo == cuts[i].CutNo && it.CutType == CutType.Rest);
                    if (restCut == null)
                    {
                        throw new Exception("余料不能为空的");
                    }

                    //计算cut长度
                    var realChildCuts = this.data.FullCuts.Where(it => it.CutParentNo == cuts[i].CutNo &&
                                                                  it.CutType != CutType.SawCut &&
                                                                  it.CutType != CutType.Trim).ToList();//加的是cuts 不需要trim
                                                                                                       //保存每个cut的结果

                    if (cuts[i].CutLevel < this.analysisLevel)//如果还在可计算的范围之内，计算每个子cut的可能性
                    {
                        List<CutResult> childCutsResult = new List<CutResult>();
                        //第一次遍历计算，获取每个cut的余料情况，判断当前cut的数据是在第一结果还是第二结果
                        for (int x = 0; x < realChildCuts.Count; x++)
                        {
                            var cut = realChildCuts[x];

                            if (cut.CutType == CutType.SawCut)
                            {
                                throw new Exception();
                            }

                            childCutsResult.Add(calculateCutRest(cut));
                        }

                        loadCuts(realChildCuts, childCutsResult, cuts[i].CutNo, pattern, cuts[i].CutW);
                        tempCuts.Clear();
                    }
                    else
                    {
                        realChildCuts = realChildCuts.Where(it => it.CutType != CutType.Rest).ToList();//再过滤一次掉rest
                        var totalCutLength = realChildCuts.Sum(it => it.CutW) + (realChildCuts.Count - 1) * cuts[i].Kerf;

                        //把切掉余料的cut也加入
                        Cut nc2 = new Cut();
                        nc2.CutD = realChildCuts[0].CutD;
                        nc2.CutLevel = cuts[i].CutLevel + 1;
                        nc2.CutNo = result1.Cuts.Count + 1;
                        nc2.CutParentNo = nc.CutNo;
                        nc2.CutPartNo = result1.Parts.Count + 1;
                        nc2.CutPatternNo = cuts[i].CutPatternNo;
                        nc2.CutQty = realChildCuts[0].CutQty;
                        nc2.CutW = totalCutLength;
                        nc2.Kerf = cuts[i].Kerf;
                        result1.Cuts.Add(nc2);

                        if (realChildCuts.Count == 1 && realChildCuts[0].CutType == CutType.Part)//如果切掉余料 刚好掉了一个真正的板件出来
                        {
                            addCutsToResult2(this.result2, realChildCuts, pattern, cuts[i].CutW, 0);
                        }
                        else//但凡需要继续子切
                        {
                            //往result1的板件里加入这么一块板
                            addPartToResult1(realChildCuts, nc2, cuts[i].CutW, pattern, cuts[i].CutPatternNo);

                            addCutsToResult2(this.result2, realChildCuts, pattern, cuts[i].CutW, 0);
                        }
                        tempCuts.Clear();
                    }
                }
            }
        }

        private void addPartToResult1(List<ExternCut> tempCuts, Cut nc, double parentCutW, Pattern pattern, int cutPatternNo)
        {
            Part part = new Part();
            if (nc.CutD == 'H')
            {
                part.PartL = tempCuts.Sum(it => it.CutW) + tempCuts[0].Kerf * (tempCuts.Count - 1);
                part.PartW = parentCutW;
            }
            else
            {
                part.PartL = parentCutW;
                part.PartW = tempCuts.Sum(it => it.CutW) + tempCuts[0].Kerf * (tempCuts.Count - 1);
            }
            part.PartQty = pattern.PatternQty;
            part.PartNo = result1.Parts.Count + 1;
            part.PartRef = $"pre{cutPatternNo}-{result2.Patterns.Count + 1}";

            var sheet = data.Sheets.Find(it => it.SheetNo == pattern.PatternSheetNumber);
            if (sheet == null)
            {
                throw new Exception();
            }
            part.PartMatNo = sheet.SheetMatNo;
            part.PartD = 0;
            result1.Parts.Add(part);
        }

        private void addCutsToResult2(R41Data result2, List<ExternCut> tempcuts, Pattern originalPattern, double parentCutW, int cutparentNo)
        {
            if (tempcuts.Count == 1 && tempcuts[0].CutType == CutType.Rest)
            {
                return;//余料切掉就切掉了 不要再生成一个pattern
            }

            //计算长宽
            double l, w;
            if (tempcuts[0].CutD == 'H')
            {
                l = tempcuts.Sum(it => it.CutW) + tempcuts[0].Kerf * (tempcuts.Count - 1);
                w = parentCutW;
            }
            else
            {
                l = parentCutW;
                w = tempcuts.Sum(it => it.CutW) + tempcuts[0].Kerf * (tempcuts.Count - 1);
            }

            //sheet
            var oldsheet = data.Sheets.Find(it => it.SheetNo == originalPattern.PatternSheetNumber);
            if (oldsheet == null)
            {
                throw new Exception("sheet not found!");
            }

            Sheet sheet = new Sheet();
            sheet.SheetL = l + 2 * this.additonalTrimValue;
            sheet.SheetW = w + 2 * this.additonalTrimValue;
            sheet.SheetThick = originalPattern.PatternThickness;
            sheet.SheetTrimMinBottom = this.additonalTrimValue;
            sheet.SheetTrimMinLeft = this.additonalTrimValue;
            sheet.SheetTrimMinRight = this.additonalTrimValue;
            sheet.SheetTrimMinUpper = this.additonalTrimValue;
            sheet.SheetNo = result2.Sheets.Count + 1;
            sheet.SheetMatNo = oldsheet.SheetMatNo;

            result2.Sheets.Add(sheet);

            //pattern 
            Pattern pa = new Pattern();
            pa.PatternNumber = result2.Patterns.Count + 1;
            //四个修边都是附加的修边值，相当于把修边加上
            pa.PatternBottomTrim = this.additonalTrimValue;
            pa.PatternLeftTrim = this.additonalTrimValue;
            pa.PatternRightTrim = this.additonalTrimValue;
            pa.PatternTopTrim = this.additonalTrimValue;
            pa.PatternQty = originalPattern.PatternQty;//todo
            pa.PatternThickness = originalPattern.PatternThickness;
            pa.PatternSheetNumber = sheet.SheetNo;
            pa.PatternL = l + 2 * additonalTrimValue;
            pa.PatternW = w + 2 * additonalTrimValue;
            Result2Comments.Add($"{originalPattern.PatternNumber}-{pa.PatternNumber}");
            Result2Parts.Add(pa.PatternNumber, data.PatternParts.Find(it => it.PatternId == originalPattern.PatternNumber));
            //pa.PatternOrientagion??

            result2.Patterns.Add(pa);

            if (tempcuts.Count == 1)//如果tempCuts只有一刀，就没有意义了
            {
                if (tempcuts[0].CutType != CutType.Rest)//余料没有子料，因为其CutNo是0，会导致各种错误
                {
                    if (tempcuts[0].CutType == CutType.Part)
                    {
                        //分两种情况，一种是block，一种是直接单块板
                        Part part = data.Parts.Find(it => it.PartNo == tempcuts[0].CutPartNo);
                        if (part.PartRef.StartsWith("block"))
                        {
                            var childCuts = this.data.BlockCuts.Where(it => it.CutPatternNo == part.PartNo && it.CutLevel == 1).ToList();
                            addResult2BlockCut(childCuts, pa.PatternNumber, 0, 1);
                        }
                        else
                        {
                            Cut cut = new Cut();
                            cut.CutD = tempcuts[0].CutD;
                            cut.CutQty = tempcuts[0].CutQty;
                            cut.CutNo = result2.Cuts.Count + 1;
                            cut.CutPartNo = 0;
                            cut.CutW = tempcuts[0].CutW;
                            cut.CutLevel = 1;
                            cut.CutParentNo = cutparentNo;//////////////////////////////////todo
                            cut.Kerf = tempcuts[0].Kerf;
                            cut.CutPatternNo = pa.PatternNumber;

                            result2.Cuts.Add(cut);

                            Cut cut2 = new Cut();
                            cut2.CutD = tempcuts[0].CutD == 'H' ? 'V' : 'H';
                            cut2.CutQty = 1;
                            cut2.CutNo = result2.Cuts.Count + 1;
                            cut2.CutPartNo = tempcuts[0].CutPartNo;
                            cut2.CutW = part.PartL == tempcuts[0].CutW ? part.PartW : part.PartL;
                            cut2.CutLevel = 2;
                            cut2.CutParentNo = cut.CutNo;//////////////////////////////////todo
                            cut2.Kerf = tempcuts[0].Kerf;
                            cut2.CutPatternNo = pa.PatternNumber;

                            result2.Cuts.Add(cut2);
                        }
                    }
                    else//strip
                    {
                        var childs = this.data.FullCuts.Where(it => it.CutParentNo == tempcuts[0].CutNo && (it.CutType == CutType.Part || it.CutType == CutType.Strip)).ToList();

                        //根据切长，返回来修改pattern和sheet的长度，使得切割的条子尺寸最小化
                        double cutlength = childs.Sum(it => (it.CutW + it.Kerf) * it.CutQty) - childs[0].Kerf;
                        if (childs[0].CutD == 'H')
                        {
                            sheet.SheetL = cutlength + 2 * additonalTrimValue;
                            pa.PatternL = sheet.SheetL;
                        }
                        else
                        {
                            sheet.SheetW = cutlength + 2 * additonalTrimValue;
                            pa.PatternW = sheet.SheetW;
                        }

                        foreach (var c in childs)
                        {
                            Cut cut = new Cut();
                            cut.CutD = c.CutD;
                            cut.CutQty = c.CutQty;
                            cut.CutNo = result2.Cuts.Count + 1;
                            cut.CutPartNo = c.CutPartNo;
                            cut.CutW = c.CutW;
                            cut.CutLevel = 1;
                            cut.CutParentNo = cutparentNo;//////////////////////////////////todo
                            cut.Kerf = c.Kerf;
                            cut.CutPatternNo = pa.PatternNumber;

                            result2.Cuts.Add(cut);

                            if (c.CutType == CutType.Strip)
                            {
                                loadResult2Cuts(c, pa.PatternNumber, 1, cut.CutNo);
                            }
                        }
                    }
                }
            }
            else
            {
                //根据切长，返回来修改pattern和sheet的长度，使得切割的条子尺寸最小化
                double cutlength = tempcuts.Where(it => it.CutType == CutType.Part || it.CutType == CutType.Strip)
                    .Max(it =>
                    {
                        if (it.CutType == CutType.Part)
                        {
                            var p = data.Parts.Find(x => x.PartNo == it.CutPartNo);
                            return p.PartL == it.CutW ? p.PartW : p.PartL;
                        }
                        else
                        {
                            var children = this.data.FullCuts.Where(x => x.CutParentNo == it.CutNo && (x.CutType == CutType.Part || x.CutType == CutType.Strip)).ToList();
                            return children.Sum(x => (x.CutW + x.Kerf) * x.CutQty) - children[0].Kerf;
                        }
                    });

                if (tempcuts[0].CutD == 'V')
                {
                    sheet.SheetL = cutlength + 2 * additonalTrimValue;
                    pa.PatternL = sheet.SheetL;
                }
                else
                {
                    sheet.SheetW = cutlength + 2 * additonalTrimValue;
                    pa.PatternW = sheet.SheetW;
                }

                //如果有板件，就要做一次trim数据的切割
                if (tempcuts.Count(it => it.CutType == CutType.Part) > 0)
                {
                    //先做一个修边
                    Cut ncut = new Cut();
                    ncut.CutD = tempcuts[0].CutD == 'H' ? 'V' : 'H';
                    ncut.CutQty = 1;
                    ncut.CutNo = result2.Cuts.Count + 1;
                    ncut.CutPartNo = 0;
                    ncut.CutW = tempcuts[0].CutD == 'H' ? w : l;
                    ncut.CutLevel = 1;
                    ncut.CutParentNo = 0;
                    ncut.Kerf = tempcuts[0].Kerf;
                    ncut.CutPatternNo = pa.PatternNumber;

                    result2.Cuts.Add(ncut);

                    foreach (var c in tempcuts)
                    {
                        Cut cut = new Cut();
                        cut.CutD = c.CutD;
                        cut.CutQty = c.CutQty;
                        cut.CutNo = result2.Cuts.Count + 1;
                        cut.CutPartNo = c.CutPartNo;
                        cut.CutW = c.CutW;
                        cut.CutLevel = 2;
                        cut.CutParentNo = ncut.CutNo;
                        cut.Kerf = c.Kerf;
                        cut.CutPatternNo = pa.PatternNumber;

                        result2.Cuts.Add(cut);

                        if (c.CutType == CutType.Strip)
                        {
                            //要把所属的子cut也都加入
                            loadResult2Cuts(c, pa.PatternNumber, 2, cut.CutNo);
                        }
                        else if (c.CutType == CutType.Part)
                        {
                            Part part = data.Parts.Find(it => it.PartNo == c.CutPartNo);
                            if (part.PartRef.StartsWith("block"))
                            {
                                var childCuts = this.data.BlockCuts.Where(it => it.CutPatternNo == part.PartNo && it.CutLevel == 1).ToList();
                                addResult2BlockCut(childCuts, pa.PatternNumber, cut.CutNo, cut.CutLevel + 1);
                            }
                        }
                    }
                }
                else
                {
                    //cuts
                    foreach (var c in tempcuts)
                    {
                        Cut cut = new Cut();
                        cut.CutD = c.CutD;
                        cut.CutQty = c.CutQty;
                        cut.CutNo = result2.Cuts.Count + 1;
                        cut.CutPartNo = c.CutPartNo;
                        cut.CutW = c.CutW;
                        cut.CutLevel = 1;
                        cut.CutParentNo = cutparentNo;/////////////////////////////////////todo
                        cut.Kerf = c.Kerf;
                        cut.CutPatternNo = pa.PatternNumber;

                        result2.Cuts.Add(cut);

                        if (c.CutType == CutType.Strip)
                        {
                            //要把所属的子cut也都加入
                            loadResult2Cuts(c, pa.PatternNumber, 1, cut.CutNo);
                        }
                    }
                }
            }
        }

        private void addResult2BlockCut(List<Cut> childCuts, int patternNumber, int parentNo, int level)
        {
            foreach (var c in childCuts)
            {
                Cut cut = new Cut();
                cut.CutD = c.CutD;
                cut.CutQty = c.CutQty;
                cut.CutNo = result2.Cuts.Count + 1;
                cut.CutPartNo = c.CutPartNo;
                cut.CutW = c.CutW;
                cut.CutLevel = level;
                cut.CutParentNo = parentNo;//////////////////////////////////todo
                cut.Kerf = c.Kerf;
                cut.CutPatternNo = patternNumber;

                result2.Cuts.Add(cut);

                if (c.CutPartNo == 0)
                {
                    var children = this.data.BlockCuts.Where(it => it.CutParentNo == c.CutNo).ToList();
                    addResult2BlockCut(children, patternNumber, cut.CutNo, level + 1);
                }
            }
        }

        private void loadResult2Cuts(ExternCut c, int patternNumber, int parentLevel, int parentNo)
        {
            var childs = this.data.FullCuts.Where(it => it.CutParentNo == c.CutNo && (it.CutType == CutType.Part || it.CutType == CutType.Strip)).ToList();
            foreach (var child in childs)
            {
                Cut cut = new Cut();
                cut.CutD = child.CutD;
                cut.CutQty = child.CutQty;
                cut.CutNo = result2.Cuts.Count + 1;
                cut.CutPartNo = child.CutPartNo;
                cut.CutW = child.CutW;
                cut.CutLevel = parentLevel + 1;
                cut.CutParentNo = parentNo;
                cut.Kerf = c.Kerf;
                cut.CutPatternNo = patternNumber;

                result2.Cuts.Add(cut);

                if (child.CutType == CutType.Strip)
                {
                    loadResult2Cuts(child, patternNumber, cut.CutLevel, cut.CutNo);
                }
                else if (child.CutType == CutType.Part)
                {
                    Part part = data.Parts.Find(it => it.PartNo == child.CutPartNo);
                    if (part.PartRef.StartsWith("block"))
                    {
                        cut.CutPartNo = 0;//important!
                        var childCuts = this.data.BlockCuts.Where(it => it.CutPatternNo == part.PartNo && it.CutLevel == 1).ToList();
                        addResult2BlockCut(childCuts, patternNumber, cut.CutNo, cut.CutLevel + 1);
                    }
                }
            }
        }

        private CutResult calculateCutRest(ExternCut cut)
        {
            if (cut.CutType == CutType.Trim)
            {
                return CutResult.Trim;
            }
            else if (cut.CutType == CutType.Part)
            {
                return CutResult.Part;
            }
            else if (cut.CutType == CutType.Rest)
            {
                if (cut.CutW < limitCutWidth)
                {
                    //return CutResult.RestFalse;
                    return CutResult.RestTrue;
                }
                else
                {
                    return CutResult.RestFalse;
                }
            }
            else if (cut.CutType == CutType.Strip)
            {
                //找余料
                var rest = this.data.FullCuts.Find(it => it.CutParentNo == cut.CutNo && it.CutType == CutType.Rest);

                //没找到余料，说明这个strip就没有余料
                if (rest == null)
                {
                    return CutResult.StripTrue;
                }

                if (rest.CutW >= limitCutWidth)
                {
                    return CutResult.StripFalse;
                }

                //根据当前的analysisLevel，判断是否继续往下一级搜索
                //得先有子strip，否则就都是板了
                var childStrips = this.data.FullCuts.Where(it => it.CutParentNo == cut.CutNo && it.CutType == CutType.Strip).ToList();
                //其次还得有级别还没超过设定的搜索深度
                if (childStrips.Count > 0 && this.analysisLevel > cut.CutLevel)
                {
                    if (childStrips.Any(c =>
                    {
                        return calculateCutRest(c) == CutResult.StripFalse;
                    }))
                    {
                        return CutResult.StripFalse;
                    }
                }

                return CutResult.StripTrue;
            }
            else
            {
                throw new Exception("unknown type");
            }
        }

        private void cleanResult2Parts()
        {
            //第一步，从结果2中，扣掉已经存在于结果1的真实板件
            foreach (var part in result1.Parts)
            {
                if (part.PartRef.StartsWith("pre"))
                {
                    continue;
                }

                //找result2中的相同板件
                for (int i = 0; i < part.PartQty; i++)
                {
                    var part2 = result2.Parts.Find(it => it.PartL == part.PartL
                                           && it.PartW == part.PartW
                                           && it.PartMatNo == part.PartMatNo
                                           && it.PartQty > 0);

                    if (part2 == null)
                    {
                        throw new Exception("part2 is null");
                    }

                    if (part2.PartQty >= 1)
                    {
                        part2.PartQty--;
                        part2.PartQtyDone--;
                    }
                    else
                    {
                        throw new Exception("part2 qty should not be zero!");
                    }
                }
            }

            //从结果2中的板件，去掉那些板件
            //先找出那些板件，找不到对应的sheet，说明对应的sheet已经不需要了
            this.result2.Parts.RemoveAll(p => this.result2.Sheets.Find(s => s.SheetMatNo == p.PartMatNo) == null);
        }

        public R41Data GetOrigin()
        {
            return data;
        }

        public R41Data GetResult1()
        {
            return result1;
        }

        public R41Data GetResult2()
        {
            return result2;
        }
    }

    public enum CutResult
    {
        Trim,
        Part,
        StripTrue,//表示strip的余料小于指定宽度
        StripFalse,
        RestTrue,//表示余料小于指定宽度
        RestFalse
    }
}
